/*
 * yauosk - Yet Another Useless Operating System Kernel
 *
 * Copyright (c) 2009-2010 Matteo Cicuttin
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 * derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/* References:
 *   [1] http://www.intel.com/design/chipsets/datashts/29056601.pdf
 */ 
 
#include <sys/types.h>
#include <arch/x86/machine.h>

/* get ioapic address from mptable */

/* See Table 1 of [1] */
#define IOAPIC_BASE		0xFEC00000

/* See Table 2 of [1] */
#define IOAPICID		0x00
#define	IOAPICVER		0x01
#define	IOAPICARB		0x02
#define	IOREDTBL		0x10
#define	REDTBL_ENTRY_LOW(irq) (2*irq)
#define	REDTBL_ENTRY_HIGH(irq) ((2*irq)+1)

#define	INT_MASKED			(1 << 16)
#define	INT_LEVEL_TRIGGER	(1 << 15)
#define	INT_ACTIVELOW		(1 << 14)
#define	INT_DST_LOGICAL		(1 << 11)

volatile u_int32_t *ioapic;

static void
ioapic_write_reg(u_int8_t offset, u_int32_t data)
{
	*ioapic = offset;
	*(ioapic + 0x10) = data;
}

static u_int32_t
ioapic_read_reg(u_int8_t offset)
{
	*ioapic = offset;
	return *(ioapic + 0x10);
}

void
ioapic_init(void)
{
	int i;
	int ioapic_id, maxrde;
	
	ioapic = (u_int32_t *)IOAPIC_BASE;
	
	ioapic_id = ioapic_read_reg(IOAPICID) >> 24;
	maxrde = (ioapic_read_reg(IOAPICVER) >> 16) & 0xFF;
	
	printf("Configuring IOAPIC(id %d, maxrde %d): interrupt", ioapic_id, maxrde);
	for (i = 0; i <= maxrde; i++)
	{
		/* Disable all interrupts */
		printf(" %d", i);
		ioapic_write_reg(REDTBL_ENTRY_LOW(i), INT_MASKED | IRQ_OFFSET+i);
		ioapic_write_reg(REDTBL_ENTRY_HIGH(i), 0);
	}
	printf("\n");
}

void
ioapic_intr_enable(int irq, int cpu)
{
	printf("ioapic_intr_enable(%d, %d)\n", irq, cpu);
	
	ioapic_write_reg(REDTBL_ENTRY_LOW(irq), IRQ_OFFSET+irq);
	ioapic_write_reg(REDTBL_ENTRY_HIGH(irq), cpu << 24);
}